package sleuthkit.util.sleuthkit.processors;

import java.awt.Cursor;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;

import sleuthkit.gui.MainApplication;
import sleuthkit.util.Node;

public class FlsProcessor extends Processor {

	private String fls = null; // = MainApplication.getInstance().getFls();
	private String name;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * sleuthkit.util.sleuthkit.processors.Processor#process(sleuthkit.util.
	 * Node, javax.swing.tree.MutableTreeNode)
	 */
	@Override
	public boolean process(Node node,
			MutableTreeNode fileDefaultMutableTreeNode, File imageFile) {
		
		log.debug("Set a wait cursor");
		MainApplication.getInstance().getFrame().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		
		if (fls == null)
			fls = MainApplication.getInstance().getFls();

		try {
			// -: Unknown type
			// r: Regular file
			// d: Directory
			// c: Character device
			// b: Block device
			// l: Symbolic link
			// p: Named FIFO
			// s: Shadow
			// h: Socket
			// w: Whiteout
			// v: TSK Virtual file / directory (not a real directory, created by
			// TSK for convenience).
			if (node.isPartitionEntry()) {
				isPartitionEntry(node,fileDefaultMutableTreeNode,imageFile);
			} else if (node.isDirectory()){
				isDirectory(node,fileDefaultMutableTreeNode,imageFile);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		log.debug("returning to a default cursor");
		MainApplication.getInstance().getFrame().setCursor(Cursor.getDefaultCursor());
		
		return super.process(node, fileDefaultMutableTreeNode, imageFile);
	}

	private void isDirectory(Node node,
			MutableTreeNode fileDefaultMutableTreeNode, File imageFile) throws IOException {
		int startoffset = node.getStartoffset();
		String executionStatment = fls + " -o " + startoffset + " "
				+ imageFile.getAbsolutePath() + " " +node.getId();
		log.debug("executionStatment = " + executionStatment);
		DefaultMutableTreeNode internaDefaultMutableTreeNode = (DefaultMutableTreeNode) fileDefaultMutableTreeNode;
		log.debug("converting the node to DefaultMutableTreeNode");
		internaDefaultMutableTreeNode.removeAllChildren();
		log.debug("remove the dummy object");
		
		Runtime runtime = Runtime.getRuntime();
		log.debug("Runtime runtime = Runtime.getRuntime() resulted in "
				+ runtime);
		log.debug("The executionStatment is " + executionStatment);
		Process executionProcess;

		executionProcess = runtime.exec(executionStatment);

		log.debug("runtime.exec resulted in " + executionProcess);
		
		BufferedReader in = new BufferedReader(new InputStreamReader(
				executionProcess.getInputStream()));
		String line = null;
		int index = 0;

		ArrayList<String> outputFls = new ArrayList<String>();
		while ((line = in.readLine()) != null) {
			log.debug(line);
			outputFls.add(line);
		}
		
		try {
			if (0 == executionProcess.waitFor()){
				for (String string : outputFls) {
					/*
					 * r/r 4: second-3.txt v/v 803763: $MBR v/v 803764:
					 * $FAT1 v/v 803765: $FAT2 d/d 803766: $OrphanFiles
					 */
					String type = string.substring(0, 3);
					log.debug("type = " + type);
					String[] lines = string.split(":");
					log.debug("lines.length = " + lines.length);
					String id = lines[0].substring(4);
					log.debug("id = " + id);
					name = lines[1].trim();
					log.debug("name = " + name);
					Node childNodeUserObject = new Node(node, type, id,
							name);
					log.debug("childNodeUserObject = "
							+ childNodeUserObject);
					DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(
							childNodeUserObject, hasLeafs(type));
					if (hasLeafs(type)){
						childNode.add(new DefaultMutableTreeNode());
					}
					log.debug("childNode = " + childNode);
					log.debug("index = " + index);
					fileDefaultMutableTreeNode.insert(childNode, index);
					index++;
				}
			}
		} catch (NumberFormatException e) {
			log.debug("NumberFormatException",e);
		} catch (InterruptedException e) {
			log.debug("InterruptedException",e);
		}
		
		
	}

	private void isPartitionEntry(Node node, MutableTreeNode fileDefaultMutableTreeNode, File imageFile) throws IOException {
		int startoffset = node.getStartoffset();
		String executionStatment = fls + " -o " + startoffset + " "
				+ imageFile.getAbsolutePath();
		Runtime runtime = Runtime.getRuntime();
		log.debug("Runtime runtime = Runtime.getRuntime() resulted in "
				+ runtime);
		log.debug("The executionStatment is " + executionStatment);
		Process executionProcess;

		executionProcess = runtime.exec(executionStatment);

		log.debug("runtime.exec resulted in " + executionProcess);
		
		BufferedReader in = new BufferedReader(new InputStreamReader(
				executionProcess.getInputStream()));
		String line = null;
		int index = 0;

		ArrayList<String> outputFls = new ArrayList<String>();
		while ((line = in.readLine()) != null) {
			log.debug(line);
			outputFls.add(line);
		}
		
		try {
			if (0 == executionProcess.waitFor()){
				for (String string : outputFls) {
					/*
					 * r/r 4: second-3.txt v/v 803763: $MBR v/v 803764:
					 * $FAT1 v/v 803765: $FAT2 d/d 803766: $OrphanFiles
					 */
					String type = string.substring(0, 3);
					log.debug("type = " + type);
					String[] lines = string.split(":");
					log.debug("lines.length = " + lines.length);
					String id = lines[0].substring(4);
					log.debug("id = " + id);
					name = lines[1].trim();
					log.debug("name = " + name);
					Node childNodeUserObject = new Node(node, type, id,
							name);
					log.debug("childNodeUserObject = "
							+ childNodeUserObject);
					DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(
							childNodeUserObject, hasLeafs(type));
					if (hasLeafs(type)){
						childNode.add(new DefaultMutableTreeNode());
					}
					log.debug("childNode = " + childNode);
					log.debug("index = " + index);
					fileDefaultMutableTreeNode.insert(childNode, index);
					index++;
				}
			}
		} catch (NumberFormatException e) {
			log.debug("NumberFormatException",e);
		} catch (InterruptedException e) {
			log.debug("InterruptedException",e);
		}
	
	}

	private boolean hasLeafs(String type) {
		// -: Unknown type
		// r: Regular file
		// d: Directory
		// c: Character device
		// b: Block device
		// l: Symbolic link
		// p: Named FIFO
		// s: Shadow
		// h: Socket
		// w: Whiteout
		// v: TSK Virtual file / directory (not a real directory, created by
		// TSK for convenience).
		return type.equalsIgnoreCase("d/d");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * sleuthkit.util.sleuthkit.processors.Processor#isProcessible(java.io.File)
	 */
	@Override
	public boolean isProcessible(File imageFile) {
		// TODO Auto-generated method stub
		return super.isProcessible(imageFile);
	}

}
